﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Text;
using System.Windows;
using Microsoft.Win32;
using 修为尽失.辅助.exts;
using 修为尽失.辅助.Resources;
using Clipboard = System.Windows.Clipboard;
using DataFormats = System.Windows.DataFormats;
using DataObject = System.Windows.DataObject;
using IDataObject = System.Windows.IDataObject;
using MenuItem = System.Windows.Controls.MenuItem;

namespace 修为尽失.辅助
{
    public static class SystemHelper
    {
         /// <summary>
         /// 获取鼠标键盘空闲时间
         /// </summary>
         /// <returns></returns>
        public static long GetIdleTick()
        {
            LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
            lastInputInfo.cbSize = Marshal.SizeOf(lastInputInfo);
            if (!GetLastInputInfo(ref　lastInputInfo)) return 0;
            return Environment.TickCount - (long)lastInputInfo.dwTime;
        }
        [StructLayout(LayoutKind.Sequential)]
        private struct LASTINPUTINFO
        {
            [MarshalAs(UnmanagedType.U4)]
            public int cbSize;
            [MarshalAs(UnmanagedType.U4)]
            public uint dwTime;
        }
        /// <summary>  
        /// 调用windows API获取鼠标键盘空闲时间  
        /// </summary>  
        /// <param name="plii"></param>  
        /// <returns></returns>  
        [DllImport("user32.dll")]
        private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
        /// <summary>
        /// 释放内存
        /// </summary>
        public static void ClearMemory()
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            if (Environment.OSVersion.Platform == PlatformID.Win32NT)
            {
                NativeMethods.SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1);
            }
        }
        public static bool IsAdministrator()
        {
            WindowsIdentity current = WindowsIdentity.GetCurrent();
            WindowsPrincipal windowsPrincipal = new WindowsPrincipal(current);
            return windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator);
        }
        public static void CopyToClipboard(string[] files, bool cut)
        {
            if (files == null)
                return;
            IDataObject data = new DataObject(DataFormats.FileDrop, files);
            var memo = new MemoryStream(4);
            var bytes = new byte[] {((byte) (cut ? 2 : 5)), 0, 0, 0};
            memo.Write(bytes, 0, bytes.Length);
            data.SetData("PreferredDropEffect", memo);
            Clipboard.SetDataObject(data, false);
        }

        /// <summary>
        /// 设置文件关联
        /// </summary>
        /// <param name="exepath">执行文件路径</param>
        /// <param name="settings">设置项形如:{{扩展名,文件类型,注册项类型},{扩展名,文件类型,注册项类型},...}</param>
        public static void f_关联文件(string exepath, string[][] settings)
        {
            try
            {
                for (var i = 0; i < settings.Length; i++)
                {
                    var si = settings[i];
                    var reg = Registry.ClassesRoot.CreateSubKey(si[0], RegistryKeyPermissionCheck.ReadWriteSubTree);
                    reg.SetValue(string.Empty, si[1]);
                    reg.SetValue("Content Type", si[2]);
                    reg = reg.CreateSubKey("shell\\open\\command");
                    reg.SetValue(string.Empty, exepath + " %1");
                    reg.Close();
                }
            }
            catch (Exception ex)
            {
                ex.ShowException();
            }
        }

        public static string f_获取桌面壁纸路径()
        {
            try
            {
                var en = Encoding.GetEncoding("unicode");
                var bytes = Registry.CurrentUser?.OpenSubKey(@"Control Panel\Desktop")?.GetValue("TranscodedImageCache") as byte[];
                if (bytes == null)
                    try
                    {
                        var wallpaper = Registry.CurrentUser?.OpenSubKey(@"Control Panel\Desktop")?.GetValue("Wallpaper")?.ToString(); //针对Windows7
                        if (wallpaper != null && System.IO.File.Exists(wallpaper))
                            return wallpaper;
                        else
                            return null;
                    }
                    catch (Exception ex)
                    {
                        ex.ShowException();
                        return null;
                    }
                else
                {
                    var transcodedImageCache = en.GetString(bytes);
                    return transcodedImageCache?.Substring(transcodedImageCache.IndexOf(':') - 1).TrimEnd('\0').Trim();
                }
            }
            catch (Exception ex)
            {
               ex.ShowException();
                return null;
            }
        }

        public static void f_加载文件打开方式子菜单(string filename, MenuItem mi)
        {
            var ext = IOHelper.GetFileExtension(filename);
            var dic = new Dictionary<string, string[]>();
            mi.Items.Clear();
            ResManager._预先加载的常见图片打开方式集合?.TryGetValue(ext, out dic);
            if (dic?.Count > 0)
            {
                foreach (var kv in dic)
                {
                    var item = new MenuItem();
                    try
                    {
                        item.Tag = new[] {kv.Key, $"\"{filename}\""};
                        var applicationCompanyInfo = (kv.Value[1] == string.Empty) ? string.Empty : ("\n\n" + kv.Value[1]);
                        item.ToolTip = $"{kv.Key}{applicationCompanyInfo}";
                        item.Click += Item_Click;
                        item.Header = kv.Value[0];
                        item.Icon = new System.Windows.Controls.Image {Source = Icon.ExtractAssociatedIcon(kv.Key)?.ToBitmap()?.ToBitmapSource()};
                    }
                    catch (Exception ex)
                    {
                      ex.ShowException();
                    }
                    finally
                    {
                        mi.Items.Add(item);
                    }
                }

                if (dic.Count > 5)
                {
                    var item = new MenuItem {Header = "哇，你一定是个图画大王！\n竟然有这么多中打开方式！\n是不是还藏着更多我没找到的呢？", Height = 80, StaysOpenOnClick = true, IsEnabled = false, FontSize = 12};
                    mi.Items.Add(item);
                }
            }
        }

        public static string f_取得当前用户HKEY_USER_Subkey() => Registry.Users.GetSubKeyNames()?.FirstOrDefault(t => t.EndsWith("Classes"));

        public enum WallpaperStyle
        {
            填充,
            适应,
            拉伸,
            平铺,
            居中,
            跨区
        }

        const int SPI_SETDESKWALLPAPER = 20;
        const int SPIF_UPDATEINIFILE = 0x01;
        const int SPIF_SENDWININICHANGE = 0x02;

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);

        public static void f_设置桌面壁纸(string paperpath, WallpaperStyle style)
        {
            var r = new object[] {false, null};
            var desktop = Registry.CurrentUser.OpenSubKey(@"Control Panel\Desktop", true);
            if(desktop==null)
                return;
            var en = Encoding.GetEncoding("unicode");
            try
            {
                switch (style)
                {
                    case WallpaperStyle.填充:
                        desktop.SetValue("TileWallpaper", "0");
                        desktop.SetValue("WallpaperStyle", "10");
                        break;
                    case WallpaperStyle.适应:
                        desktop.SetValue("TileWallpaper", "0");
                        desktop.SetValue("WallpaperStyle", "6");
                        break;
                    case WallpaperStyle.拉伸:
                        desktop.SetValue("TileWallpaper", "0");
                        desktop.SetValue("WallpaperStyle", "2");
                        break;
                    case WallpaperStyle.平铺:
                        desktop.SetValue("TileWallpaper", "1");
                        desktop.SetValue("WallpaperStyle", "0");
                        break;
                    case WallpaperStyle.居中:
                        desktop.SetValue("TileWallpaper", "0");
                        desktop.SetValue("WallpaperStyle", "0");
                        break;
                    case WallpaperStyle.跨区:
                        desktop.SetValue("TileWallpaper", "0");
                        desktop.SetValue("WallpaperStyle", "22");
                        break; 
                }

                SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, paperpath, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
                r[0] = true;
                r[1] = "设置壁纸成功！";
            }
            catch (Exception ex)
            {
               ex.ShowException();
                try
                {
                    desktop.SetValue("TranscodedImageCache", en.GetBytes(paperpath), RegistryValueKind.Binary);
                }
                catch (Exception exi)
                {
                    r[0] = false;
                    r[1] = exi.Message;
                }
            }
            finally
            {
                desktop.Close();
                if (!(bool) r[0])
                   MessageHelper.ShowWarning(r[1].ToString()); 
            }
        }

        public static object[] f_设置桌面壁纸(string pathtoset, int o)
        {
            var r = new object[] {false, null};
            var p1 = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Microsoft\\Windows\\Themes\\TranscodedWallpaper~";
            try
            {
                var bmp = new Bitmap(pathtoset);
                bmp.Save(p1, ImageFormat.Bmp);
                NativeMethods.SystemParametersInfo(20, 0, p1, 0x2);
                r[0] = true;
                r[1] = "设置成功！";
            }
            catch (Exception ex)
            {
                r[0] = false;
                r[1] = ex.ToLogString();
                return r;
            }

            return r;
        }

        public static Dictionary<string, string[]> GetValidMuiCacheDictionary()
        {
            var dic = new Dictionary<string, string[]>();
            var MuiCacheNames = Registry.Users.OpenSubKey($@"{ResManager.当前用户HKEY_USER_Subkey}\Local Settings\Software\Microsoft\Windows\Shell\MuiCache")?.GetValueNames();
            if (MuiCacheNames != null)
                foreach (var item in MuiCacheNames)
                {
                    var i = item.LastIndexOf('.');
                    if (i == -1)
                        continue;
                    var a = item.Substring(0, i);
                    var b = item.Substring(i + 1);
                    if (dic.ContainsKey(a))
                    {
                        if (b != "FriendlyAppName")
                            dic[a][1] = Registry.Users.OpenSubKey($@"{ResManager.当前用户HKEY_USER_Subkey}\Local Settings\Software\Microsoft\Windows\Shell\MuiCache")?.GetValue(item)?.ToString() ?? string.Empty;
                    }
                    else
                    {
                        if (System.IO.File.Exists(a))
                        {
                            var infos = new string[2];
                            var info = Registry.Users.OpenSubKey($@"{ResManager.当前用户HKEY_USER_Subkey}\Local Settings\Software\Microsoft\Windows\Shell\MuiCache")?.GetValue(item)?.ToString() ?? string.Empty;
                            if (b.Equals("FriendlyAppName"))
                                infos[0] = info;
                            else
                                infos[1] = info;
                            dic.Add(a, infos);
                        }
                    }
                }

            return dic;
        }

          internal static Dictionary<string, Dictionary<string, string[]>> f_加载文件打开方式子菜单集合数据()
        {
            var _预先加载的常见图片打开方式集合 = new Dictionary<string, Dictionary<string, string[]>>();
            foreach (var ext in ResManager.Strings.Windows常见图像文件过滤后缀名数组)
                try
                {
                    var dss = new Dictionary<string, string[]>();
                    var OpenWithList = Registry.ClassesRoot.OpenSubKey($@"{ext}\OpenWithList")?.GetSubKeyNames();
                    var OpenWithProgids = Registry.ClassesRoot.OpenSubKey($@"{ext}\OpenWithProgids")?.GetValueNames();
                    var OpenWithList2 = Registry.CurrentUser.OpenSubKey($@"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\{ext}\OpenWithList")?.GetValueNames();
                    if (OpenWithList2 != null)
                        ReadItemsFromRegistry_OpenWithList(dss, OpenWithList2, ext);
                    if (OpenWithList != null)
                        ReadItemsFromRegistry_OpenWithList(dss, OpenWithList, ext);
                    if (OpenWithProgids != null)
                        ReadItemsFromRegistry_openWithProgids(dss, OpenWithProgids, ext);
                    if (!dss.ContainsKey(ResManager.Mspaint.Key))
                        dss.Add(ResManager.Mspaint.Key, ResManager.Mspaint.Value);
                    _预先加载的常见图片打开方式集合.Add(ext, dss);
                }
                catch (Exception ex)
                {
                   ex.ShowException();
                }

            return _预先加载的常见图片打开方式集合;
        }

        private static void Item_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var s = sender as MenuItem;
                var cmd = s?.Tag as string[];
                if (cmd != null)
                    Process.Start(cmd[0], cmd[1]);
            }
            catch (Exception ex)
            {
                ex.ShowException();
            }
        }

        private static void ReadItemsFromRegistry_OpenWithList(Dictionary<string, string[]> dss, string[] OpenWithList, string ext)
        {
            for (var i = 0; i < OpenWithList.Length; i++)
                try
                {
                    var kn = OpenWithList[i];
                    var vn = Registry.CurrentUser.OpenSubKey($@"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\{ext}\OpenWithList")?.GetValue(kn)?.ToString();
                    if (!vn.IsNullOrEmpty())
                    {
                        var kv = ResManager.ValidMuiCacheDictionary.FirstOrDefault(a => a.Key.EndsWith(vn));
                        if ((kv.Key != null) && (!dss.ContainsKey(kv.Key)))
                            dss.Add(kv.Key, kv.Value);
                    }
                }
                catch (Exception ex)
                {
                    ex.ShowException();
                }
        }

        private static void ReadItemsFromRegistry_openWithProgids(Dictionary<string, string[]> dss, string[] openWithProgids, string ext)
        {
            for (var i = 0; i < openWithProgids.Length; i++)
            {
                var vn = openWithProgids[i];
                var shells = Registry.ClassesRoot.OpenSubKey($@"{vn}")?.OpenSubKey("shell")?.GetSubKeyNames();
                if (shells != null)
                    for (var j = 0; j < shells.Length; j++)
                    {
                        var shell = shells[j];
                        if (shell.Equals("printto"))
                            continue;
                        try
                        {
                            var cmd = Registry.ClassesRoot.OpenSubKey($@"{vn}\shell\{shell}")?.OpenSubKey("command")?.GetValue(string.Empty)?.ToString();
                            if (!string.IsNullOrEmpty(cmd))
                            {
                                var cmd0 = cmd.Split(new[] {" \""}, StringSplitOptions.RemoveEmptyEntries)[0].Trim('\"');
                                if ((!dss.ContainsKey(cmd0)) && System.IO.File.Exists(cmd0))
                                    if (vn.Contains("file") || vn.Contains(ext))
                                        dss.Add(cmd0, new[] {Path.GetFileNameWithoutExtension(cmd0), string.Empty});
                                    else
                                        dss.Add(cmd0, new[] {vn, string.Empty});
                            }
                        }
                        catch
                        {
                        }
                    }
            }
        }

        public class Win32
        {
            public static IntPtr FindWindowByClass(string className) => NativeMethods.FindWindow((string) null, className);
            public static IntPtr FindWindowByClass(IntPtr handlerParent, string childClassName) => NativeMethods.FindWindowEx(handlerParent, 0, childClassName, (string) null);
            public static IntPtr FindWindowByClass(int handlerChildAfter, string childClassName) => NativeMethods.FindWindowEx(IntPtr.Zero, handlerChildAfter, childClassName, (string) null);
            public static IntPtr FindWindowByClass(IntPtr handlerParent, int handlerChildAfter, string childClassName) => NativeMethods.FindWindowEx(handlerParent, handlerChildAfter, childClassName, (string) null);
            public static IntPtr FindWindowByText(string windowName) => NativeMethods.FindWindow((string) null, windowName);
            public static IntPtr FindWindowByText(IntPtr handlerParent, string childWindowName) => NativeMethods.FindWindowEx(handlerParent, 0, (string) null, childWindowName);
            public static IntPtr FindWindowByText(IntPtr handlerParent, int handlerChildAfter, string childWindowName) => NativeMethods.FindWindowEx(handlerParent, handlerChildAfter, (string) null, childWindowName);

            /// <summary>
            /// 定义了辅助键的名称（将数字转变为字符以便于记忆，也可去除此枚举而直接使用数值）
            /// </summary>
            [Flags()]
            public enum KeyModifiers
            {
                None = 0,
                Alt = 1,
                Ctrl = 2,
                Shift = 4,
                WindowsKey = 8
            }

            /// <summary>
            /// 热键的对应的消息ID
            /// </summary>
            public const int WmHotkey = 0x312;
        }

        public static class PrimaryScreen
        {
            [DllImport("user32.dll")]
            static extern IntPtr GetDC(IntPtr ptr);

            [DllImport("gdi32.dll")]
            static extern int GetDeviceCaps(IntPtr hdc, int nIndex);

            [DllImport("user32.dll", EntryPoint = "ReleaseDC")]
            static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);

            const int HORZRES = 8;
            const int VERTRES = 10;
            const int LOGPIXELSX = 88;
            const int LOGPIXELSY = 90;
            const int DESKTOPVERTRES = 117;
            const int DESKTOPHORZRES = 118;

            /// <summary>  
            /// 获取屏幕分辨率当前物理大小  
            /// </summary>  
            public static System.Windows.Size WorkingArea
            {
                get
                {
                    IntPtr hdc = GetDC(IntPtr.Zero);
                    var size = new System.Windows.Size();
                    size.Width = GetDeviceCaps(hdc, HORZRES);
                    size.Height = GetDeviceCaps(hdc, VERTRES);
                    ReleaseDC(IntPtr.Zero, hdc);
                    return size;
                }
            }

            /// <summary>  
            /// 当前系统DPIX 大小 一般为96  
            /// </summary>  
            public static int DpiX
            {
                get
                {
                    IntPtr hdc = GetDC(IntPtr.Zero);
                    int DpiX = GetDeviceCaps(hdc, LOGPIXELSX);
                    ReleaseDC(IntPtr.Zero, hdc);
                    return DpiX;
                }
            }

            /// <summary>  
            /// 当前系统DPIY 大小 一般为96  
            /// </summary>  
            public static int DpiY
            {
                get
                {
                    IntPtr hdc = GetDC(IntPtr.Zero);
                    int DpiX = GetDeviceCaps(hdc, LOGPIXELSY);
                    ReleaseDC(IntPtr.Zero, hdc);
                    return DpiX;
                }
            }

            /// <summary>  
            /// 获取真实设置的桌面分辨率大小  
            /// </summary>  
            public static System.Windows.Size DESKTOP
            {
                get
                {
                    IntPtr hdc = GetDC(IntPtr.Zero);
                    var size = new System.Windows.Size();
                    size.Width = GetDeviceCaps(hdc, DESKTOPHORZRES);
                    size.Height = GetDeviceCaps(hdc, DESKTOPVERTRES);
                    ReleaseDC(IntPtr.Zero, hdc);
                    return size;
                }
            }

            /// <summary>  
            /// 获取宽度缩放百分比  
            /// </summary>  
            public static float ScaleX
            {
                get
                {
                    IntPtr hdc = GetDC(IntPtr.Zero);
                    int t = GetDeviceCaps(hdc, DESKTOPHORZRES);
                    int d = GetDeviceCaps(hdc, HORZRES);
                    float ScaleX = (float) GetDeviceCaps(hdc, DESKTOPHORZRES) / (float) GetDeviceCaps(hdc, HORZRES);
                    ReleaseDC(IntPtr.Zero, hdc);
                    return ScaleX;
                }
            }

            /// <summary>  
            /// 获取高度缩放百分比  
            /// </summary>  
            public static float ScaleY
            {
                get
                {
                    IntPtr hdc = GetDC(IntPtr.Zero);
                    float ScaleY = (float) (float) GetDeviceCaps(hdc, DESKTOPVERTRES) / (float) GetDeviceCaps(hdc, VERTRES);
                    ReleaseDC(IntPtr.Zero, hdc);
                    return ScaleY;
                }
            }
        }
    }
}